package translate;

import Base.ResourceTest;
import EntityBuilder.RenterBuilder;
import com.huawei.translate.api.TranslateApi;
import com.huawei.translate.model.Renter;
import com.huawei.translate.provider.MSTranslateProvider;
import com.huawei.translate.service.TranslateRecordService;
import com.huawei.translate.vo.*;
import com.huawei.translate.vo.translate.TranslateArrayRequest;
import com.huawei.translate.vo.translate.TranslateArrayResponse;
import com.huawei.translate.vo.translate.TranslateResponse;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.when;

@RunWith(SpringRunner.class)
public class When_request_array_translate extends ResourceTest {

    private Renter renter;

    @Autowired
    @Mock
    private MSTranslateProvider msTranslateProvider;

    @Autowired
    @Mock
    private TranslateRecordService translateRecordService;

    @Autowired
    @InjectMocks
    private TranslateApi translateApi;

    @Before
    public void injectMocks() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void should_log_when_request_translate_array() {

        renter = new RenterBuilder(renterRepository).WithAppSecret(UUID.randomUUID().toString()).Build();
        ResponseEntity<AccessTokenResponse> accessTokenResponse = generateAccessToken();

        ArrayList<String> texts = new ArrayList<>();
        texts.add("Hello");

        TranslateArrayRequest request = new TranslateArrayRequest(accessTokenResponse.getBody().getAccessToken(), "en", "to", texts);

        sendTranslateRequestWithHeader(request, "Hello").getBody();

        Mockito.verify(translateRecordService).record(isA(TranslateArrayRequest.class), isA(List.class), anyString(), anyString());
    }

    @Test
    public void should_return_bad_request_when_request_invalid() {
        TranslateArrayRequest request = new TranslateArrayRequest();
        request.setAccessToken("hello");
        request.setFrom("en");
        request.setTo("en");
        request.setTexts(new ArrayList<>());

        ResponseEntity<TranslateArrayResponse> responseEntity = this.testRestTemplate.postForEntity("/api/translates/array", request, TranslateArrayResponse.class);

        TranslateArrayResponse response = responseEntity.getBody();

        Assert.assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
        Assert.assertEquals(HttpStatus.BAD_REQUEST.value(), response.getCode());
    }

    @Test
    public void should_return_bad_request_when_accessToken_invalid() {

        ArrayList<String> texts = new ArrayList<>();
        texts.add("Hello");
        TranslateArrayRequest request = new TranslateArrayRequest("invalidAccessToken", "en", "to", texts);

        ResponseEntity<TranslateArrayResponse> responseEntity = this.testRestTemplate.postForEntity("/api/translates/array", request, TranslateArrayResponse.class);

        Assert.assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
        Assert.assertEquals(HttpStatus.FORBIDDEN.value(), responseEntity.getBody().getCode());
    }

    @Test
    public void should_return_translate_result_when_request_valid() {
        List<String> rs = new ArrayList<>();
        rs.add("Hello");

        when(msTranslateProvider.translate(isA(TranslateArrayRequest.class))).thenReturn(rs);

        renter = new RenterBuilder(renterRepository).WithAppSecret(UUID.randomUUID().toString()).Build();
        ResponseEntity<AccessTokenResponse> accessTokenResponse = generateAccessToken();
        ArrayList<String> texts = new ArrayList<>();
        texts.add("Hello");
        TranslateArrayRequest request = new TranslateArrayRequest(accessTokenResponse.getBody().getAccessToken(), "en", "to", texts);

        ResponseEntity<TranslateArrayResponse> responseEntity = this.testRestTemplate.postForEntity("/api/translates/array", request, TranslateArrayResponse.class);

        Assert.assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
        Assert.assertEquals(HttpStatus.OK.value(),responseEntity.getBody().getCode());
        Assert.assertEquals(1, responseEntity.getBody().getMessages().size());
        Assert.assertEquals("Hello", responseEntity.getBody().getMessages().get(0));
    }

    @Test
    public void should_bad_request_when_cannot_request() {

        when(msTranslateProvider.translate(isA(TranslateArrayRequest.class))).thenReturn(null);

        renter = new RenterBuilder(renterRepository).WithAppSecret(UUID.randomUUID().toString()).Build();
        ResponseEntity<AccessTokenResponse> accessTokenResponse = generateAccessToken();
        ArrayList<String> texts = new ArrayList<>();
        texts.add("Hello");
        TranslateArrayRequest request = new TranslateArrayRequest(accessTokenResponse.getBody().getAccessToken(), "en", "to", texts);

        ResponseEntity<TranslateArrayResponse> responseEntity = this.testRestTemplate.postForEntity("/api/translates/array", request, TranslateArrayResponse.class);

        Assert.assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
        Assert.assertEquals(HttpStatus.BAD_REQUEST.value(),responseEntity.getBody().getCode());
    }

    private ResponseEntity<AccessTokenResponse> sendGenerateAccessTokenRequest(AccessTokenGenerateRequest request) {
        return this.testRestTemplate.postForEntity("/api/oauth/generate", request, AccessTokenResponse.class);
    }

    private ResponseEntity<AccessTokenResponse> generateAccessToken() {
        return sendGenerateAccessTokenRequest(new AccessTokenGenerateRequest(renter.getAppSecret(), "Secret"));
    }

    private ResponseEntity<TranslateResponse> sendTranslateRequestWithHeader(TranslateArrayRequest request, String traceId) {
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.add("traceid", traceId);
        HttpEntity httpEntity = new HttpEntity(request, requestHeaders);
        return this.testRestTemplate.exchange("/api/translates/array", HttpMethod.POST, httpEntity, TranslateResponse.class);
    }
}
